﻿using System.Collections.Generic;
using System.Linq;
using SharedTypes;

namespace AdaptationProject.Utils
{
    /// <summary>
    /// Контейнер, содержащий список загруженных алгоритмов исполнительного файла, 
    /// алгоритмов адаптации параметров и их настройки.
    /// </summary>
    public static class ResContainer
    {
        /// <summary>
        /// Счётчик количeства загруженных алгоритмов исполнительного файла.
        /// </summary>
        private static int localAlgCompressCounter;

        /// <summary>
        /// Счётчик количeства загруженных универсальных алгоритмов.
        /// </summary>
        private static int localAlgUniversalCounter;

        /// <summary>
        /// Счётчик количества загруженных методов адаптации параметров.
        /// </summary>
        private static int localMethodCounter;

        /// <summary>
        /// Контейнер алгоритмов исполнительного файла 
        /// <порядковый номер,<имя (ключ), объект алгоритма (значение>>.
        /// </summary>
        private static Dictionary<int, KeyValuePair<string, IAlgorithm>> AlgorithmsCompress = 
            new Dictionary<int, KeyValuePair<string, IAlgorithm>>();

        /// <summary>
        /// Контейнер универсальногоалгоритмов исполнительного файла 
        /// <порядковый номер,<имя (ключ), объект алгоритма (значение>>.
        /// </summary>
        private static Dictionary<int, KeyValuePair<string, IAlgorithm>> AlgorithmsUniversal =
            new Dictionary<int, KeyValuePair<string, IAlgorithm>>();

        /// <summary>
        /// Контейнер методов адаптации параметров
        /// <порядковый номер,<имя (ключ), объект алгоритма (значение>>.
        /// </summary>
        private static Dictionary<int, KeyValuePair<string, IAdoptationMethod>> Methods = 
            new Dictionary<int, KeyValuePair<string, IAdoptationMethod>>();

        /// <summary>
        /// Контейнер, содержащий параметры по умолчанию для методов адаптации.
        /// </summary>
        private static Dictionary<int, List<ParameterAttribute>> DefaultMethodsParameters = 
            new Dictionary<int, List<ParameterAttribute>>();

        /// <summary>
        /// Контейнер пользовательских параметров для методов адаптации.
        /// </summary>
        private static Dictionary<int, List<object>> CustomMethodParameters =
            new Dictionary<int, List<object>>();

        /// <summary>
        /// Добавляет алгоритм исполнительного файла в контейнер.
        /// </summary>
        /// <param name="toAdd">Пара ключ (имя алгоритма) значение(объект алгоритма).</param>
        public static void AddAlgorithm(KeyValuePair<string, IAlgorithm> toAdd)
        {
            AlgorithmsCompress.Add(localAlgCompressCounter, toAdd);
            localAlgCompressCounter++;
        }
         /// <summary>
        /// Добавляет универсальный алгоритм в контейнер.
        /// </summary>
        /// <param name="toAdd">Пара ключ (имя алгоритма) значение(объект алгоритма).</param>
        public static void AddUniveralAlgorithm(KeyValuePair<string, IAlgorithm> toAdd)
        {
            AlgorithmsUniversal.Add(localAlgUniversalCounter, toAdd);
            localAlgUniversalCounter++;
        }

        
        /// <summary>
        /// Добавляет метод адаптации в контейнер.
        /// </summary>
        /// <param name="toAdd">Пара ключ (имя метода) значение (объект метода).</param>
        /// <param name="parameterAttributes">Список доступных пользлователю параметров.</param>
        public static void AddMethod(KeyValuePair<string, IAdoptationMethod> toAdd, List<ParameterAttribute> parameterAttributes)
        {
            Methods.Add(localMethodCounter, toAdd);
            DefaultMethodsParameters.Add(localMethodCounter, parameterAttributes);
            localMethodCounter++;
        }

        /// <summary>
        /// Устанавливает пользовательские параметры для метода адаптации.
        /// </summary>
        /// <param name="algId">Идентификатор метода.</param>
        /// <param name="parameters">Список объектов (параметров) метода 
        /// (порядок и количество должны строго совпадать).</param>
        public static void SetCustomMethodParameters(int algId, List<object> parameters)
        {
            if (CustomMethodParameters.ContainsKey(algId))
            {
                CustomMethodParameters.Remove(algId);
            }
            CustomMethodParameters.Add(algId, parameters);
        }

        /// <summary>
        /// Получает алгоритм исполнительного файла по идентификатору.
        /// </summary>
        /// <param name="index">Идентификатор алгоритма.</param>
        /// <param name="alg">Объект алгоритма (выходной параметр).</param>
        /// <returns>Истина если загрузка была успешной, иначе - ложь.</returns>
        public static bool GetAlgorithm(int index, out IAlgorithm alg)
        {
            bool result = false;
            if ((localAlgCompressCounter > 0 && index >= 0) && (index < localAlgCompressCounter))
            {
                result = true;
                alg = AlgorithmsCompress[index].Value;
            }
            else
            {
                alg = null;
            }
            return result;
        }

        /// <summary>
        /// Получает универсальный алгоритм по идентификатору.
        /// </summary>
        /// <param name="index">Идентификатор алгоритма.</param>
        /// <param name="alg">Объект алгоритма (выходной параметр).</param>
        /// <returns>Истина если загрузка была успешной, иначе - ложь.</returns>
        public static bool GetUniversalAlgorithm(int index, out IAlgorithm alg)
        {
            bool result = false;
            if ((localAlgUniversalCounter > 0 && index >= 0) && (index < localAlgUniversalCounter))
            {
                result = true;
                alg = AlgorithmsUniversal[index].Value;
            }
            else
            {
                alg = null;
            }
            return result;
        }

        /// <summary>
        /// Получает метод адаптации по идентификатору.
        /// </summary>
        /// <param name="index">Идентификатор метода.</param>
        /// <param name="mtd">Объект метода (выходной параметр).</param>
        /// <returns>Истина если загрузка была успешной, иначе - ложь.</returns>
        public static bool GetMethod(int index, out IAdoptationMethod mtd)
        {
            bool result = false;
            if ((localMethodCounter > 0 && index >= 0) && (index < localMethodCounter))
            {
                result = true;
                mtd = Methods[index].Value;
            }
            else
            {
                mtd = null;
            }
            return result;
        }

        /// <summary>
        /// Возвращает список всех доступных алгоритмов исполнительного файла.
        /// </summary>
        /// <returns>Список алгоритмов исполнительного файла.</returns>
        public static List<KeyValuePair<string, IAlgorithm>> GetAllCompressAlgorithms()
        {
            var algs = from entry in AlgorithmsCompress
                       select entry.Value;
            return algs.ToList();
        }

        /// <summary>
        /// Возвращает список всех доступных алгоритмов исполнительного файла.
        /// </summary>
        /// <returns>Список алгоритмов исполнительного файла.</returns>
        public static List<KeyValuePair<string, IAlgorithm>> GetAllUniversalAlgorithms()
        {
            var algs = from entry in AlgorithmsUniversal
                       select entry.Value;
            return algs.ToList();
        }

        /// <summary>
        /// Возвращает список всех доступных методов адаптации.
        /// </summary>
        /// <returns>Список методов адаптации.</returns>
        public static List<KeyValuePair<string, IAdoptationMethod>> GetAllMethods()
        {
            var methods = from entry in Methods
                          select entry.Value;
            return methods.ToList();
        }

        /// <summary>
        /// Получает список параметров метода адаптации (по умолчанию).
        /// </summary>
        /// <param name="methodId">Идентификатор метода.</param>
        /// <returns>Список параметров метода.</returns>
        public static List<ParameterAttribute> GetDefaultMethodParameters(int methodId)
        {
            List<ParameterAttribute> toRet = null;
            if (DefaultMethodsParameters.ContainsKey(methodId))
            {
                toRet = DefaultMethodsParameters[methodId];
            }
            return toRet;
        }

        /// <summary>
        /// Очищает контейннер алгоритмов.
        /// </summary>
        public static void ClearAlgorithmsCompress()
        {
            AlgorithmsCompress.Clear();
            localAlgCompressCounter = 0;
        }

        /// <summary>
        /// Очищает контейннер универсальных алгоритмов.
        /// </summary>
        public static void ClearAlgorithmsUniversal()
        {
            AlgorithmsUniversal.Clear();
            localAlgUniversalCounter = 0;
        }

        /// <summary>
        /// Очищает контейнер методов. 
        /// </summary>
        public static void ClearMethods()
        {
            Methods.Clear();
            DefaultMethodsParameters.Clear();
            CustomMethodParameters.Clear();
            localMethodCounter = 0;
        }

        /// <summary>
        /// Очищает контейнеры методов и алгоритмов.
        /// </summary>
        public static void ClearAll()
        {
            ClearAlgorithmsCompress();
            ClearMethods();
        }

        /// <summary>
        /// Возвращает список пользовательских параметров метода адаптации.
        /// </summary>
        /// <param name="selectedIndex">Идентификатор метода.</param>
        /// <returns>Список пользовательских параметров метода.</returns>
        public static List<object> GetMethodCustomParameters(int selectedIndex)
        {
            List<object> toRet = null;
            if (CustomMethodParameters.ContainsKey(selectedIndex))
            {
                toRet = CustomMethodParameters[selectedIndex];
            }
            return toRet;
        }

        /// <summary>
        /// Возвращает параметр метода адаптации. (по порядковому номеру).
        /// </summary>
        /// <param name="selectedIndex">Идентификатор метода.</param>
        /// <param name="order">Порядковый номер параметра.</param>
        /// <returns>Объект параметра метода.</returns>
        public static object GetMethodCustomParameterByOrderNum(int selectedIndex, int order)
        {
            object toRet = null;
            if (CustomMethodParameters.ContainsKey(selectedIndex))
            {
                toRet = CustomMethodParameters[selectedIndex][order];
            }
            return toRet;
        }
    }
}
